package main;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Control;

/** Created by JinMiao 2020/5/20. */
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(1)
@Warmup(iterations = 1)
@Measurement(iterations = 3)
@State(Scope.Group)
public class MpmcBenchmark {

  public static final String PARAM_UNSAFE = "MpmcArrayQueue";
  public static final String PARAM_AFU = "MpmcAtomicArrayQueue";
  public static final String PARAM_JDK = "ArrayBlockingQueue";

  public static final int PRODUCER_THREADS_NUMBER = 4;
  public static final int CONSUMER_THREADS_NUMBER = 4;

  public static final String GROUP_NAME = "MyGroup";

  public static final int CAPACITY = 128;

  @Param({PARAM_UNSAFE, PARAM_AFU, PARAM_JDK})
  public volatile String implementation;

  public volatile Queue<Long> queue;

  @Setup(Level.Trial)
  public void setUp() {
    switch (implementation) {
      case PARAM_UNSAFE:
        // queue = new MpmcArrayQueue<>(CAPACITY);
        break;
      case PARAM_AFU:
        // queue = new MpmcAtomicArrayQueue<>(CAPACITY);
        break;
      case PARAM_JDK:
        queue = new ArrayBlockingQueue<>(CAPACITY);
        break;
      default:
        throw new UnsupportedOperationException("Unsupported implementation " + implementation);
    }
  }

  @Benchmark
  @Group(GROUP_NAME)
  @GroupThreads(PRODUCER_THREADS_NUMBER)
  public void write(Control control) {
    while (!control.stopMeasurement && !queue.offer(1L)) {}
  }

  @Benchmark
  @Group(GROUP_NAME)
  @GroupThreads(CONSUMER_THREADS_NUMBER)
  public void read(Control control) {
    while (!control.stopMeasurement && queue.poll() == null) {}
  }
}
